#include <stdio.h>

#include "../cJSON/cJSON.h"

// "interest": {
// 	"basketball": "篮球",
// 	"badminton": "羽毛球"
// }

/**
 * @brief  {}
 * @note   
 * @param [in]
 * @param [out]
 * @retval 
 */
int cJSON_analyze_demo1(void)
{
    char *JSON_data = 
    "{                                     \
        \"interest\":                      \
            {                              \
                \"basketball\":\"篮球\",    \
                \"badminton\":\"羽毛球\"    \
            }                              \
    }";


    cJSON *root = NULL;
    cJSON *item = NULL;

    char *v_str = NULL;

    /* 解析整段JSO数据 */
    root = cJSON_Parse(JSON_data);
    if(root == NULL)
    {
        printf("parse fail.\n");
        return -1;
    }

	printf("方式一：\n");
	item = cJSON_GetObjectItem(root, "interest");		// 获取object对象名
	if (item != NULL) 
    {
		cJSON *val = NULL;

		val = cJSON_GetObjectItem(item, "basketball");	// 根据object对象名获得里面的basketball数据
		if (val != NULL && val->type == cJSON_String) {
			v_str = val->valuestring;
			printf("basketball = %s\n", v_str);
		}

		val = cJSON_GetObjectItem(item, "badminton");	// 根据object对象名获得里面的badminton数据
		if (val != NULL && val->type == cJSON_String) {
			v_str = val->valuestring;
			printf("badminton = %s\n", v_str);
		}
	}

	printf("方式二：\n");
	item = cJSON_GetObjectItem(root, "interest");
	if (item != NULL) {
		cJSON *obj = item->child;	// 获得 "basketball":	"篮球"

		while (obj) {
			if (obj->type == cJSON_String) {
				char *v_str = obj->valuestring;
				printf("%s = %s\n", obj->string, v_str);	// 可以通过string获得键
			}
			// 获取下一个元素
			obj = obj->next;
		}
	}
    return 0;
}

// "color": [ "black", "white"]

/**
 * @brief  []
 * @note   
 * @param [in]
 * @param [out]
 * @retval 
 */
int cJSON_analyze_demo2(void)
{
    char *JSON_data = 
    "{                                    \
        \"color\": [\"black\", \"white\"]\
    }";

    cJSON *root = NULL;
    cJSON *item = NULL;

    char *v_str = NULL;

    /* 解析整段JSO数据 */
    root = cJSON_Parse(JSON_data);
    if(root == NULL)
    {
        printf("parse fail.\n");
        return -1;
    }

	printf("方式一：\n");
	item = cJSON_GetObjectItem(root, "color");
	if (item != NULL) {
		int size = cJSON_GetArraySize(item);	// 获得数组个数

		for (int i = 0; i < size; i++) {
			cJSON *arr = cJSON_GetArrayItem(item, i);	// 根据索引获得数组中的值

			if (arr != NULL && arr->type == cJSON_String) {
				v_str = arr->valuestring;
				printf("color = %s\n", v_str);
			}
		}
	}


	printf("方式二：\n");
	item = cJSON_GetObjectItem(root, "color");
	if (item != NULL) {
		cJSON *arr = item->child;	// 获得 "black"

		while (arr) {
			if (arr->type == cJSON_String) {
				char *v_str = arr->valuestring;
				printf("color = %s\n", v_str);
			}
			// 获取下一个元素
			arr = arr->next;
		}
	}
    return 0;
}

// "subject": [
// 	{ "name": "语文", "score": 70 },
// 	{ "name": "数学", "score": 88.5 },
// ]

/**
 * @brief  [ { }, { } ]
 * @note   
 * @param [in]
 * @param [out]
 * @retval 
 */
int cJSON_analyze_demo3(void)
{
    char *JSON_data = 
    "{                                    \
        \"subject\": [                    \
            {                             \
                \"name\": \"语文\",        \
                \"score\": 70.5           \
            },                            \
            {                             \
                \"name\": \"数学\",        \
                \"score\": 88.5           \
            }                             \
        ]                                 \
    }";

    cJSON *root = NULL;
    cJSON *item = NULL;

    char *v_str = NULL;
    double v_double = 0.0;

    /* 解析整段JSO数据 */
    root = cJSON_Parse(JSON_data);
    if(root == NULL)
    {
        printf("parse fail.\n");
        return -1;
    }

    printf("方式一：\n");
	item = cJSON_GetObjectItem(root, "subject");
	if (item != NULL) {
		int size = cJSON_GetArraySize(item);	// 获取的数组大小

		for (int i = 0; i < size; i++) {
			cJSON *obj = cJSON_GetArrayItem(item, i);		// 获取的数组里的obj
			cJSON *val = NULL;

			if (obj != NULL && obj->type == cJSON_Object) {	// 判断数字内的元素是不是obj类型
				val = cJSON_GetObjectItem(obj, "name");		// 获得obj里的值

				if (val != NULL && val->type == cJSON_String) {
					v_str = val->valuestring;
					printf("name = %s\n", v_str);
				}

				val = cJSON_GetObjectItem(obj, "score");
				if (val != NULL && val->type == cJSON_Number) {
					v_double = val->valuedouble;
					printf("score = %.2f\n", v_double);
				}
			}
		}
	}


	printf("方式二：\n");
	item = cJSON_GetObjectItem(root, "subject");
	if (item != NULL) {
		cJSON *obj = item->child;	// 获得 { "name": "语文", "score": 70.5 }

		while (obj) {
			if (obj->type == cJSON_Object) {

				cJSON *objValue = obj->child;	// 获得 "name": "语文"
				while (objValue) {

					// 再通过类型去区分
					if (objValue->type == cJSON_String) {
						char *v_str = objValue->valuestring;
						printf("%s = %s\n", objValue->string, v_str);

					} else if (objValue->type == cJSON_Number) {
						double v_double = objValue->valuedouble;
						printf("%s = %.2f\n", objValue->string, v_double);
					}
					// 获取下一个元素
					objValue = objValue->next;
				}
			}
			// 获取下一组元素
			obj = obj->next;
		}
	}

    return 0;
}

// "education": [
//     [ "小学", "初中" ],
//     [ "高中", "大学" ]
// ]

/**
 * @brief  [ [ ], [ ] ]
 * @note   
 * @param [in]
 * @param [out]
 * @retval 
 */
int cJSON_analyze_demo4(void)
{
    char *JSON_data = 
    "{                                    \
        \"education\": [                  \
            [ \"小学\",\"初中\"],          \
            [ \"高中\",\"大学\"]           \
        ]                                 \
    }";

    cJSON *root = NULL;
    cJSON *item = NULL;

    char *v_str = NULL;

    /* 解析整段JSO数据 */
    root = cJSON_Parse(JSON_data);
    if(root == NULL)
    {
        printf("parse fail.\n");
        return -1;
    }

    printf("方式一：\n");
	item = cJSON_GetObjectItem(root, "education");
	if (item != NULL) {
		int size = cJSON_GetArraySize(item);	// 获取的数组大小

		for (int i = 0; i < size; i++) {
			cJSON *arr = cJSON_GetArrayItem(item, i);		// 解析获得	[ "小学", "初中" ]

			if (arr != NULL && arr->type == cJSON_Array) {
				int arrSize = cJSON_GetArraySize(arr);

				for (int j = 0; j < arrSize; j++) {
					cJSON *arr2 = cJSON_GetArrayItem(arr, j);	// 再进一步解析就可以得到数组里面的元素了

					if (arr2 != NULL && arr2->type == cJSON_String) {
						v_str = arr2->valuestring;
						printf("education = %s\n", v_str);
					}
				}
			}
		}
	}

	printf("方式二：\n");
	item = cJSON_GetObjectItem(root, "education");
	if (item != NULL) {
		cJSON *arr = item->child;	// 获得 [ "小学", "初中" ]

		while (arr) {
			if (arr->type == cJSON_Array) {
			
				cJSON *arrValue = arr->child;	// 获得 "小学"
				while (arrValue) {
					if (arrValue->type == cJSON_String) {
						char *v_str = arrValue->valuestring;
						printf("education = %s\n", v_str);
					}
					arrValue = arrValue->next;	// 获取下一个元素
				}
			}
			// 获取下一组
			arr = arr->next;
		}
	}

    return 0;
}

// "languages": {
// 	"serialOne": { "language": "汉语", "grade": 10 },
// 	"serialTwo": { "language": "英语", "grade": 6}
// }

/**
 * @brief  { { }, { } }
 * @note   
 * @param [in]
 * @param [out]
 * @retval 
 */
int cJSON_analyze_demo5(void)
{
    char *JSON_data = 
    "{                                    \
        \"languages\":                    \
            {                             \
                \"serialOne\": {          \
                    \"language\": \"汉语\",\
                    \"grade\": 10         \
                },                        \
	            \"serialTwo\": {          \
                    \"language\":         \
                    \"英语\",              \
                    \"grade\": 6          \
                }                         \
            }                             \
    }";

    cJSON *root = NULL;
    cJSON *item = NULL;

    char *v_str = NULL;
    int v_int = 0;
    /* 解析整段JSO数据 */
    root = cJSON_Parse(JSON_data);
    if(root == NULL)
    {
        printf("parse fail.\n");
        return -1;
    }

    printf("方式一：\n");
	char *arrStr[] = { "serialOne", "serialTwo" };		// 可以提前定义需要解析的对象键，这样就可以使用for循环进行解析了

	item = cJSON_GetObjectItem(root, "languages");
	if (item != NULL) {
		cJSON *val = NULL;
		int size = sizeof(arrStr) / sizeof(char *);

		// 通过遍历指针数组，获得每个对象的键，在进行解析操作（如果不使用for循环解析，那就老老实实的写代码将全部个数解析完毕）
		for (int i = 0; i < size; i++) {
			cJSON *obj1 = cJSON_GetObjectItem(item, arrStr[i]);

			if (obj1 != NULL && obj1->type == cJSON_Object) {

				val = cJSON_GetObjectItem(obj1, "language");
				if (val != NULL && val->type == cJSON_String) {
					v_str = val->valuestring;
					printf("education = %s\n", v_str);
				}

				val = cJSON_GetObjectItem(obj1, "grade");
				if (val != NULL && val->type == cJSON_Number) {
					v_int = val->valueint;
					printf("grade = %d\n", v_int);
				}
			}
		}
	}

    printf("方式二：\n");
	// 在不知道键是什么的情况下 和 不知道有多少元素的情况下可用
	item = cJSON_GetObjectItem(root, "languages");
	if (item != NULL) {
		// 获取到languages里的第一个子元素
		cJSON *obj = item->child;	// 也就是："serialOne": { "language": "汉语", "grade": 10 }

		while (obj) {
			if (obj->type == cJSON_Object) {

				// 获取到子元素的子元素
				cJSON *value = obj->child;	// 也就是：{ "language": "汉语", "grade": 10 }

				while (value) {
					if (value->type == cJSON_String) {
						printf("%s = %s\n", value->string, value->valuestring);

					} else if (value->type == cJSON_Number) {
						printf("%s = %d\n", value->string, value->valueint);
					}
					// 通过next可以自由获取里面的元素了
					value = value->next;
				}
			}

			// 获得下一组子元素
			obj = obj->next;
		}
	}

    return 0;
}

int cJSON_analyze_demo(void)
{
    char *JSON_data = 
    "{                              \
        \"name\":\"sumu\",   \
        \"age\": 28,                \
        \"weight\": 69.8,           \
        \"address\":                \
            {                       \
                \"country\": \"China\",\
                \"city\": \"shagnhai\",\
                \"zip-code\": 999999\
            },                      \
        \"skill\": [\"c\", \"html\", \"Python\"],\
        \"student\": false          \
    }";

    cJSON* root = NULL;

    cJSON* cjson_name = NULL;
    cJSON* cjson_age = NULL;
    cJSON* cjson_weight = NULL;

    cJSON* cjson_address = NULL;
    cJSON* cjson_address_country = NULL;
    cJSON* cjson_address_city = NULL;
    cJSON* cjson_address_zipcode = NULL;

    cJSON* cjson_skill = NULL;
    cJSON* cjson_skill_item = NULL;
    int    skill_array_size = 0;
    int    i = 0;

    cJSON* cjson_student = NULL;

    /* 解析整段JSO数据 */
    root = cJSON_Parse(JSON_data);
    if(root == NULL)
    {
        printf("parse fail.\n");
        return -1;
    }

    /* 依次根据名称提取JSON数据（键值对） */
    cjson_name = cJSON_GetObjectItem(root, "name");
    cjson_age = cJSON_GetObjectItem(root, "age");
    cjson_weight = cJSON_GetObjectItem(root, "weight");

    printf("name: %s\n", cjson_name->valuestring);
    printf("age:%d\n", cjson_age->valueint);
    printf("weight:%.1f\n", cjson_weight->valuedouble);

    /* 解析嵌套json数据 */
    cjson_address = cJSON_GetObjectItem(root, "address");
    cjson_address_country = cJSON_GetObjectItem(cjson_address, "country");
    cjson_address_city = cJSON_GetObjectItem(cjson_address, "city");
    cjson_address_zipcode = cJSON_GetObjectItem(cjson_address, "zip-code");
    printf("address-country:%s\naddress-city:%s\naddress-zipcode:%d\n", 
        cjson_address_country->valuestring, cjson_address_city->valuestring, cjson_address_zipcode->valueint);

    /* 解析数组 */
    cjson_skill = cJSON_GetObjectItem(root, "skill");
    skill_array_size = cJSON_GetArraySize(cjson_skill);
    printf("skill:[");
    for(i = 0; i < skill_array_size; i++)
    {
        cjson_skill_item = cJSON_GetArrayItem(cjson_skill, i);
        printf("%s,", cjson_skill_item->valuestring);
    }
    printf("\b]\n");

    /* 解析布尔型数据 */
    cjson_student = cJSON_GetObjectItem(root, "student");
    if(cjson_student->valueint == 0)
    {
        printf("student: false\n");
    }
    else
    {
        printf("student:error\n");
    }
    return 0;
}
int main(void)
{
    // cJSON_analyze_demo1();
    // cJSON_analyze_demo2();
    // cJSON_analyze_demo3();
    // cJSON_analyze_demo4();
    // cJSON_analyze_demo5();
    cJSON_analyze_demo();
    return 0;
}
